using System;
using System.IO;
using System.Xml;

namespace Graphe.Data
{
    public class IndexProvider
    {
        #region Singleton

        private static IndexProvider _instance;

        public static IndexProvider Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new IndexProvider();

                return _instance;
            }
        }

        #endregion

        /// <summary>
        /// Gets an index from disk.
        /// </summary>
        /// <param name="directory">The directory in which to look for an index file.</param>
        /// <returns>Object of type Index or null, if no index is found.</returns>
        public Index GetIndex(string directory)
        {
            string filename = directory + "\\Index.xml";
            if (File.Exists(filename))
            {
                Index index = new Index();
                index.FileName = filename;

                XmlDocument doc = new XmlDocument();
                doc.Load(filename);

                index.ManuscriptName = doc.DocumentElement.Attributes["ManuscriptName"].Value;

                foreach(XmlNode node in doc.DocumentElement.SelectSingleNode("Items").ChildNodes)
                {
                    IndexItem item = new IndexItem();

                    XmlNode nameNode = node.SelectSingleNode("Name");
                    XmlNode imageNumberNode = node.SelectSingleNode("StartImage");

                    if(nameNode != null)
                        item.Name = nameNode.InnerText;

                    if (imageNumberNode != null)
                        item.ImageNumber = Convert.ToInt32(imageNumberNode.InnerText);

                    index.Items.Add(item);
                }

                XmlNode imageReferencesNode = doc.DocumentElement.SelectSingleNode("ImageReferences");

                if (imageReferencesNode != null)
                {
                    foreach (XmlNode node in imageReferencesNode.ChildNodes)
                    {
                        ImageReference reference = new ImageReference();

                        reference.FileName = node.Attributes["FileName"].Value;
                        reference.StartReference = node.Attributes["StartReference"].Value;
                        reference.EndReference = node.Attributes["EndReference"].Value;

                        index.ImageReferences.Add(reference);
                    }
                }

                return index;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Exports the index to a text file.
        /// </summary>
        /// <param name="index">The index to export.</param>
        /// <param name="filePath">The path to the location at which the exported text file is to be stored.</param>
        public void ExportToTextFile(Index index, string filePath)
        {
            using (StreamWriter writer = File.CreateText(filePath))
            {
                foreach (ImageReference reference in index.ImageReferences)
                {
                    writer.WriteLine(reference.FileName + ":  " + reference.StartReference);
                }
            }
        }

        public void Save(Index index)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml("<Index ManuscriptName=\"\"><Items /><ImageReferences /></Index>");

            doc.DocumentElement.Attributes["ManuscriptName"].Value = index.ManuscriptName;

            XmlNode itemsNode = doc.DocumentElement.SelectSingleNode("Items");
            foreach (IndexItem item in index.Items)
            {
                XmlElement itemElement = doc.CreateElement("Item");
                itemsNode.AppendChild(itemElement);

                XmlElement nameElement = doc.CreateElement("Name");
                itemElement.AppendChild(nameElement);
                nameElement.InnerText = item.Name;

                XmlElement imageNumberElement = doc.CreateElement("ImageNumber");
                itemElement.AppendChild(imageNumberElement);
                imageNumberElement.InnerText = item.ImageNumber.ToString();
            }

            System.Collections.Generic.SortedList<string, ImageReference> sortedImageReferences = new System.Collections.Generic.SortedList<string, ImageReference>();
            foreach (ImageReference reference in index.ImageReferences)
                sortedImageReferences.Add(reference.FileName, reference);

            XmlNode imageReferencesNode = doc.DocumentElement.SelectSingleNode("ImageReferences");
            foreach (string key in sortedImageReferences.Keys)
            {
                ImageReference reference = sortedImageReferences[key];
                XmlElement imageElement = doc.CreateElement("Image");
                imageReferencesNode.AppendChild(imageElement);

                XmlAttribute attFileName = doc.CreateAttribute("FileName");
                imageElement.Attributes.Append(attFileName);
                attFileName.Value = reference.FileName;

                XmlAttribute attStartReference = doc.CreateAttribute("StartReference");
                imageElement.Attributes.Append(attStartReference);
                attStartReference.Value = reference.StartReference;

                XmlAttribute attEndReference = doc.CreateAttribute("EndReference");
                imageElement.Attributes.Append(attEndReference);
                attEndReference.Value = reference.EndReference;
            }

            doc.Save(index.FileName);
        }

        public Index CreateIndex(string directoryPath, string indexName)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml("<Index><Items /><ImageReferences /></Index>");

            if (!String.IsNullOrEmpty(indexName))
            {
                XmlAttribute att = doc.CreateAttribute("ManuscriptName");
                att.Value = indexName;
                doc.DocumentElement.Attributes.Append(att);
            }
            doc.Save(directoryPath + "\\Index.xml");

            return GetIndex(directoryPath);
        }
    }
}
